package ${table.basePackage}.service.impl;

<#-- 获取主键字段类型 -->
<#assign pkType = "Long">
<#list columns as c>
  <#if (c.isPk?? && c.isPk) || (c.propertyName?? && c.propertyName?lower_case == "id")>
    <#if c.javaType?? && (c.javaType?contains("String") || c.javaType == "String")>
      <#assign pkType = "String">
    <#elseif c.javaType?? && c.javaType != "">
      <#assign pkType = c.javaType?split(".")?last>
    </#if>
    <#break>
  </#if>
</#list>

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kexio.common.converter.EntityDTOConverter;
import com.kexio.common.dto.PageResponse;
import com.kexio.common.excel.ExcelUtils;
import com.kexio.common.exception.BusinessException;
import com.kexio.common.page.PageConverters;
import com.kexio.common.page.PageUtils;
import ${table.basePackage}.dto.${table.entityName}DTO;
import ${table.basePackage}.entity.${table.entityName};
import ${table.basePackage}.mapper.${table.entityName}Mapper;
import ${table.basePackage}.service.${table.entityName}Service;

/**
 * ${table.comment!table.entityName} - 服务实现类
 * 
 * 遵循Kexio开发规范：
 * - 使用 EntityDTOConverter 进行实体和DTO转换
 * - 使用 ExcelUtils 处理导入导出
 * - 异常统一抛出，由全局异常处理器捕获
 * - 事务边界清晰，确保数据一致性
 * - 租户ID通过BaseEntity自动处理
 * 
 * @author ${user.name!"系统"}
 * @since ${now?string('yyyy-MM-dd HH:mm:ss')}
 */
@Service
@Transactional(readOnly = true)
public class ${table.entityName}ServiceImpl implements ${table.entityName}Service {
    
    private static final Logger logger = LoggerFactory.getLogger(${table.entityName}ServiceImpl.class);

    @Autowired
    private ${table.entityName}Mapper ${lowerEntity}Mapper;

    @Override
    public PageResponse<${table.entityName}DTO> queryPage(${table.entityName}DTO queryDTO) {
        // 规范化分页参数
        long current = PageUtils.normalizePageNo(queryDTO.getCurrent());
        long size = PageUtils.normalizePageSize(queryDTO.getSize());
        
        // 构建查询条件
        LambdaQueryWrapper<${table.entityName}> wrapper = buildQueryWrapper(queryDTO);
        
        // 执行分页查询
        Page<${table.entityName}> page = ${lowerEntity}Mapper.selectPage(new Page<>(current, size), wrapper);
        
        // 转换为DTO并返回
        return PageConverters.convertWithMapping(page, 
            entity -> EntityDTOConverter.toDTO(entity, ${table.entityName}DTO.class));
    }

    @Override
    public ${table.entityName}DTO getDetail(${pkType} id) {
        if (id == null) {
            throw BusinessException.badRequest("ID不能为空");
        }
        
        ${table.entityName} entity = ${lowerEntity}Mapper.selectById(id);
        if (entity == null) {
            throw BusinessException.resourceNotFound("${table.comment!table.entityName}不存在");
        }
        
        ${table.entityName}DTO dto = EntityDTOConverter.toDTO(entity, ${table.entityName}DTO.class);
        
<#if table.templateType?has_content && table.templateType == 'multi' && table.ext?? && table.ext.relations??>
        // 加载关联数据
  <#list table.ext.relations as r>
        // TODO: 加载 ${r.alias} 关联数据
        // 示例代码：
        // List<${r.entityClass}> ${r.alias}Entities = ${r.alias}Mapper.selectList(
        //     new LambdaQueryWrapper<${r.entityClass}>()
        //         .eq(${r.entityClass}::get${r.foreignKey?cap_first}, id)
        // );
        // dto.set${r.alias?cap_first}(EntityDTOConverter.toDTOList(${r.alias}Entities, ${r.dtoClass}.class));
        log.warn("子表查询逻辑未实现：{} - 请手动实现", "${r.alias}");
  </#list>
</#if>
        
        return dto;
    }

    @Override
    public List<${table.entityName}DTO> queryList(${table.entityName}DTO queryDTO) {
        LambdaQueryWrapper<${table.entityName}> wrapper = buildQueryWrapper(queryDTO);
        List<${table.entityName}> entities = ${lowerEntity}Mapper.selectList(wrapper);
        
        return entities.stream()
            .map(entity -> EntityDTOConverter.toDTO(entity, ${table.entityName}DTO.class))
            .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ${table.entityName}DTO create(${table.entityName}DTO dto) {
        // 转换为实体
        ${table.entityName} entity = EntityDTOConverter.toEntity(dto, ${table.entityName}.class);
        
        // 插入数据库
        ${lowerEntity}Mapper.insert(entity);
        
        // 返回DTO
        return EntityDTOConverter.toDTO(entity, ${table.entityName}DTO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ${table.entityName}DTO update(${pkType} id, ${table.entityName}DTO dto) {
        if (id == null) {
            throw BusinessException.badRequest("ID不能为空");
        }
        
        // 检查是否存在
        ${table.entityName} existing = ${lowerEntity}Mapper.selectById(id);
        if (existing == null) {
            throw BusinessException.resourceNotFound("${table.comment!table.entityName}不存在");
        }
        
        // 将DTO的非null值复制到existing实体（避免覆盖未修改的字段）
        EntityDTOConverter.updateEntity(dto, existing);
        
        // 更新数据库
        ${lowerEntity}Mapper.updateById(existing);
        
        // 返回更新后的DTO
        return EntityDTOConverter.toDTO(existing, ${table.entityName}DTO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(${pkType} id) {
        if (id == null) {
            throw BusinessException.badRequest("ID不能为空");
        }
        
        int rows = ${lowerEntity}Mapper.deleteById(id);
        if (rows == 0) {
            throw BusinessException.resourceNotFound("${table.comment!table.entityName}不存在或已被删除");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(List<${pkType}> ids) {
        if (ids == null || ids.isEmpty()) {
            throw BusinessException.badRequest("ID列表不能为空");
        }
        
        ${lowerEntity}Mapper.deleteBatchIds(ids);
    }

<#if table.templateType?has_content && table.templateType == 'multi'>
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ${table.entityName}DTO createWithRelations(${table.entityName}DTO dto) {
        // 1. 保存主表
        ${table.entityName}DTO result = create(dto);
        
  <#if table.ext?? && table.ext.relations??>
        // 2. 保存关联数据
    <#list table.ext.relations as r>
        if (dto.get${r.alias?cap_first}() != null && !dto.get${r.alias?cap_first}().isEmpty()) {
            for (${r.dtoClass} item : dto.get${r.alias?cap_first}()) {
                // 设置外键
                // TODO: 根据实际情况调整外键设置方式，如：item.set${r.foreignKey?cap_first}(result.getId());
                // 保存子表
                // TODO: 注入子表Mapper并调用insert，如：${r.alias}Mapper.insert(EntityDTOConverter.toEntity(item, ${r.entityClass}.class));
                log.warn("子表保存逻辑未实现：{} - 请手动实现", "${r.alias}");
            }
        }
    </#list>
  </#if>
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ${table.entityName}DTO updateWithRelations(${pkType} id, ${table.entityName}DTO dto) {
        // 1. 更新主表
        ${table.entityName}DTO result = update(id, dto);
        
  <#if table.ext?? && table.ext.relations??>
        // 2. 处理关联数据
    <#list table.ext.relations as r>
        if (dto.get${r.alias?cap_first}() != null) {
            // 删除旧的关联数据
            // TODO: 注入子表Mapper并删除，如：${r.alias}Mapper.delete(new LambdaQueryWrapper<${r.entityClass}>().eq(${r.entityClass}::get${r.foreignKey?cap_first}, id));
            
            // 插入新的关联数据
            for (${r.dtoClass} item : dto.get${r.alias?cap_first}()) {
                // 设置外键
                // TODO: 根据实际情况调整外键设置方式，如：item.set${r.foreignKey?cap_first}(id);
                // 保存子表
                // TODO: 注入子表Mapper并调用insert，如：${r.alias}Mapper.insert(EntityDTOConverter.toEntity(item, ${r.entityClass}.class));
                log.warn("子表更新逻辑未实现：{} - 请手动实现", "${r.alias}");
            }
        }
    </#list>
  </#if>
        
        return result;
    }

</#if>
    @Override
    public void exportData(${table.entityName}DTO queryDTO, OutputStream outputStream) throws IOException {
        // 查询数据
        List<${table.entityName}DTO> dataList = queryList(queryDTO);
        
        // 数据量限制（防止内存溢出）
        if (dataList.size() > 100000) {
            throw BusinessException.badRequest("导出数据量过大（超过10万条），请添加筛选条件");
        }
        
        // 使用 ExcelUtils 导出
        ExcelUtils.exportExcel(dataList, ${table.entityName}DTO.class, outputStream);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> importData(InputStream inputStream, boolean updateSupport) throws IOException {
        // 使用 ExcelUtils 读取数据
        List<${table.entityName}DTO> dtoList = ExcelUtils.importExcel(inputStream, ${table.entityName}DTO.class);
        
        int total = dtoList.size();
        int successCount = 0;
        int failureCount = 0;
        List<String> errorMessages = new ArrayList<>();
        
        for (int i = 0; i < dtoList.size(); i++) {
            ${table.entityName}DTO dto = dtoList.get(i);
            try {
                if (updateSupport) {
                    // 更新逻辑：根据ID判断是更新还是创建
                    // TODO: 如果需要根据其他唯一字段（如code）判断，请修改此处逻辑
<#list columns as c>
  <#if (c.isPk?? && c.isPk) || (c.propertyName?? && c.propertyName?lower_case == "id")>
                    if (dto.get${c.propertyName?cap_first}() != null) {
                        ${table.entityName} existing = ${lowerEntity}Mapper.selectById(dto.get${c.propertyName?cap_first}());
                        if (existing != null) {
                            // 存在则更新
                            update(dto.get${c.propertyName?cap_first}(), dto);
                        } else {
                            // 不存在则创建
                            create(dto);
                        }
                    } else {
                        // ID为空则创建
                        create(dto);
                    }
    <#break>
  </#if>
</#list>
                } else {
                    // 不支持更新，直接创建
                    create(dto);
                }
                successCount++;
            } catch (Exception e) {
                failureCount++;
                errorMessages.add(String.format("第%d行导入失败: %s", i + 2, e.getMessage()));
                logger.error("导入第{}行失败", i + 2, e);
            }
        }
        
        // 返回导入结果
        Map<String, Object> result = new HashMap<>();
        result.put("total", total);
        result.put("successCount", successCount);
        result.put("failureCount", failureCount);
        result.put("errorMessages", errorMessages);
        
        return result;
    }

    @Override
    public void downloadImportTemplate(OutputStream outputStream) throws IOException {
        // 创建空数据列表作为模板
        List<${table.entityName}DTO> templateList = new ArrayList<>();
        
        // 可以添加一行示例数据
        // ${table.entityName}DTO example = new ${table.entityName}DTO();
        // // 设置示例值...
        // templateList.add(example);
        
        // 导出模板
        ExcelUtils.exportExcel(templateList, ${table.entityName}DTO.class, outputStream);
    }

    /**
     * 构建查询条件
     *
     * @param queryDTO 查询DTO
     * @return 查询Wrapper
     */
    private LambdaQueryWrapper<${table.entityName}> buildQueryWrapper(${table.entityName}DTO queryDTO) {
        LambdaQueryWrapper<${table.entityName}> wrapper = new LambdaQueryWrapper<>();
        
        if (queryDTO == null) {
            return wrapper;
        }
        
        // 根据字段类型和名称智能选择查询方式
<#list columns as c>
  <#if c.propertyName?? && c.propertyName != "id">
    <#assign skipField = false>
    <#if c.columnName?? && (c.columnName?lower_case == "tenant_id" || c.columnName?lower_case == "create_by" || c.columnName?lower_case == "create_time" || c.columnName?lower_case == "create_date" || c.columnName?lower_case == "update_by" || c.columnName?lower_case == "update_time" || c.columnName?lower_case == "update_date" || c.columnName?lower_case == "deleted" || c.columnName?lower_case == "version")>
      <#assign skipField = true>
    </#if>
    <#if !skipField>
      <#if c.javaType?? && (c.javaType?contains("Date") || c.javaType?contains("LocalDateTime") || c.javaType?contains("LocalDate") || c.javaType?contains("Timestamp"))>
        // ${c.comment!(c.propertyName!'')} - 时间范围查询
        wrapper.ge(queryDTO.get${c.propertyName?cap_first}Start() != null, ${table.entityName}::get${c.propertyName?cap_first}, queryDTO.get${c.propertyName?cap_first}Start());
        wrapper.le(queryDTO.get${c.propertyName?cap_first}End() != null, ${table.entityName}::get${c.propertyName?cap_first}, queryDTO.get${c.propertyName?cap_first}End());
      <#elseif c.javaType?? && (c.javaType?contains("String") || c.javaType == "String")>
        <#-- 根据字段名判断是精确查询还是模糊查询 -->
        <#if c.propertyName?lower_case?ends_with("code") || c.propertyName?lower_case?ends_with("no") || c.propertyName?lower_case?ends_with("id")>
        // ${c.comment!(c.propertyName!'')} - 精确查询
        wrapper.eq(StringUtils.hasText(queryDTO.get${c.propertyName?cap_first}()), ${table.entityName}::get${c.propertyName?cap_first}, queryDTO.get${c.propertyName?cap_first}());
        <#else>
        // ${c.comment!(c.propertyName!'')} - 模糊查询
        wrapper.like(StringUtils.hasText(queryDTO.get${c.propertyName?cap_first}()), ${table.entityName}::get${c.propertyName?cap_first}, queryDTO.get${c.propertyName?cap_first}());
        </#if>
      <#else>
        // ${c.comment!(c.propertyName!'')} - 精确查询
        wrapper.eq(queryDTO.get${c.propertyName?cap_first}() != null, ${table.entityName}::get${c.propertyName?cap_first}, queryDTO.get${c.propertyName?cap_first}());
      </#if>
    </#if>
  </#if>
</#list>
        
        return wrapper;
    }
}
